package com.yql.common.utils.logs;

import cn.hutool.json.JSONUtil;
import com.yql.common.utils.DateUtils;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;


public class CommonLogUtil {

    private static final String COLON = ":";

    private static final String LEFT_BRACKET = "(";

    private static final String RIGHT_BRACKET = ")";

    private static final String MINUS_SIGN = " - ";

    private static final Logger LOGGER = LoggerFactory.getLogger(CommonLogUtil.class);

    /**
     * 打印info级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param newThrowable 创建一个Throwable对象,获取日志发生行所属的类、方法及行号
     * @param mess         日志模板 xxx{}
     * @param objects      日志模板中替代占位符的值
     */
    public static void info(Throwable newThrowable, String mess, Object... objects) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info(append(newThrowable, mess), addTraceId(objects));
        }
    }

    /**
     * 打印warn级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param objects 日志模板中替代占位符的值
     */
    public static void warn(Throwable newThrowable, String mess, Object... objects) {
        if (LOGGER.isWarnEnabled()) {
            LOGGER.warn(append(newThrowable, mess), addTraceId(objects));
        }
    }

    /**
     * 打印debug级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param newThrowable 创建一个Throwable对象,获取日志发生行所属的类、方法及行号
     * @param mess         日志模板 xxx{}
     * @param objects      日志模板中替代占位符的值
     */
    public static void debug(Throwable newThrowable, String mess, Object... objects) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(append(newThrowable, mess), addTraceId(objects));
        }
    }

    /**
     * 打印error级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param newThrowable 创建一个Throwable对象,获取日志发生行所属的类、方法及行号
     * @param mess         日志模板 xxx{}
     */
    public static void error(Throwable newThrowable, String mess, Object... objs) {
        LOGGER.error(appendErrorMess(newThrowable, mess, objs));
    }

    /**
     * 打印error级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param newThrowable 创建一个Throwable对象,获取日志发生行所属的类、方法及行号
     * @param mess         日志模板 xxx{}
     * @param th           异常或错误
     */
    public static void error(Throwable newThrowable, String mess, Throwable th) {
        LOGGER.error(appendErrorMess(newThrowable, mess), th);
    }

    /**
     * 打印error级别日志,自动在日志消息前添加"[traceId=xxx],"
     *
     * @param newThrowable 创建一个Throwable对象,获取日志发生行所属的类、方法及行号
     * @param mess         日志模板 xxx{}
     * @param th           异常或错误
     */
    public static void error(Throwable newThrowable, String mess, Throwable th, Object... objs) {
        LOGGER.error(appendErrorMess(newThrowable, mess, objs), th);
    }

    /**
     * 拼接基本日志信息
     *
     * @param th
     * @return
     */
    private static StringBuffer appendBasicMess(Throwable th) {
        StringBuffer buffer = new StringBuffer();
        StackTraceElement element = th.getStackTrace()[0];
        buffer.append(element.getClassName()).append(LEFT_BRACKET).append(element.getMethodName())
                .append(COLON).append(element.getLineNumber()).append(RIGHT_BRACKET).append(MINUS_SIGN);
        return buffer;
    }

    /**
     * 拼接info,debug级别的日志信息
     *
     * @param
     * @param mess
     * @return
     */
    private static String append(Throwable th, String mess) {
        return appendBasicMess(th).append("[traceId={}],").append(mess).toString();
    }

    /**
     * 拼接error级别的日志信息
     *
     * @param th
     * @param mess
     * @return
     */
    private static String appendErrorMess(Throwable th, String mess) {
        return appendBasicMess(th).append("[traceId=").append(com.yql.common.utils.logs.TraceContextUtil.getTraceId())
                .append("],").append(mess).toString();
    }

    /**
     * 拼接error级别的日志信息
     *
     * @param th
     * @param mess
     * @param objs
     * @return
     */
    private static String appendErrorMess(Throwable th, String mess, Object... objs) {
        if (objs != null) {
            for (Object obj : objs) {
                if (obj == null) {
                    mess = mess.replaceFirst("\\{\\}", "");
                    continue;
                }
                String str = null;
                if (obj instanceof Date) {
                    str = DateUtils.dateTime((Date) obj);
                } else {
                    str = JSONUtil.toJsonPrettyStr(obj);
                }
                mess = mess.replaceFirst("\\{\\}", str);
            }
        }
        return appendBasicMess(th).append("[traceId=").append(com.yql.common.utils.logs.TraceContextUtil.getTraceId())
                .append("],").append(mess).toString();
    }

    /**
     * 数组首位添加traceId
     *
     * @param objects
     * @return
     */
    private static Object[] addTraceId(Object[] objects) {
        if (objects == null) {
            objects = new Object[0];
        }
        Object[] objs = new Object[objects.length + 1];
        if(TraceContextUtil.getTraceId() == null){
            String uuid = UUID.randomUUID().toString().replace("-", "");
            TraceContextUtil.setTraceId(uuid);
        }
        objs[0] = TraceContextUtil.getTraceId();

        System.arraycopy(objects, 0, objs, 1, objects.length);
        return objs;
    }
}
